﻿using Builder;
using ConfigurationUtility;
using DataModel;
using GlobalUtility;
using HslCommunication;
using HslCommunication.ModBus;
using LogCentre;
using System;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace TSC
{
    public delegate void CableDisabledEventHandler(byte CableId, bool valid);
    //public delegate void DataEventHandler();
    public delegate void DataEventHandler(int DeviceId);
    public class ModbusStation
    {
        private string ip;
        private string port;
        private byte startId;
        private byte endId;
        private int ConnectInterval;
        private int ReadInterval;
        private ModbusTcpNet master;
        private ConfigUtility configUtility;

        public int deviceId { get; }

        public event CableDisabledEventHandler CableDisabledEvent;
        public event DataEventHandler ConnectionFailureEvent ;
        public event DataEventHandler CloseEvent;

        //public ModbusStation(string ip, string port, byte _startId, byte _endId)
        //{

        //    this.ip = ip;
        //    this.port = port;
        //    this.startId = _startId;
        //    this.endId = _endId;
        //    //tempCache = cache;
        //}

        public ModbusStation(ConfigUtility _configUtility, int _ConnectInterval)
        {
            this.configUtility = _configUtility;
           this. ConnectInterval = _ConnectInterval;
            this.deviceId =Convert.ToInt32(configUtility.GetValue(Constant_Fields.DeviceID));
            this.ip = configUtility.GetValue(Constant_Fields.Cable1IP);
            this.port = configUtility.GetValue(Constant_Fields.CablePort);
            startId = Convert.ToByte(configUtility.GetValue(Constant_Fields.StartStation));
            endId = Convert.ToByte(configUtility.GetValue(Constant_Fields.EndStation));
            ReadInterval = Convert.ToInt32(configUtility.GetValue(Constant_Fields.ReadInterval));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="result"></param>
        /// <returns></returns>
        private bool ReadTemprature(byte station, out short[] result)
        {
            result = new short[0];
            //bool ret = false;
            try
            {
                //master.Station = station;
                if (GlobalVar.TEMP_CONN_STATE)
                {
                    string address = "s="+station+ ";x=3;1";
                    OperateResult<short[]> num = master.ReadInt16(address, 15);
                    if (num.IsSuccess)
                    {
                        result = num.Content;
                        StringBuilder sb = new StringBuilder();
                        sb.Clear();
                        sb.Append(" 数据读取成功！");
                        sb.Append(" Station ID: " + station);
                        MainLog.Info(sb.ToString(), true);

                        return true;
                    }
                    else
                    {
                        StringBuilder sb = new StringBuilder();
                        sb.Clear();
                        sb.Append(" ErrorCode:" + num.ErrorCode);
                        sb.Append(" Message:" + num.Message);
                        sb.Append(" Station ID: " + station);
                        master.ConnectClose();
                        Task.Delay(5000);
                        master.ConnectServer();
                        MainLog.Error(sb.ToString(), true);
                    }
                }
            }
            catch (Exception ex)
            {
                MainLog.Error(ex.ToString(), false);
            }
            //connState = false;
            //master.ConnectClose();
            //master.Dispose();
            return false;
        }

        internal void Start()
        {
            try
            {
                //检查Cable1连接状态
                if (!GlobalVar.TEMP_CONN_STATE && !GlobalVar.disableCache)
                {
                    bool conState = Connect();
                    if (conState)
                    {
                        GlobalVar.TEMP_CONN_STATE = conState;
                        MainLog.Info("感温电缆连接成功", true);
                        Task.Run(() => ReadTemprature());
                        BuilderStatus.SetStart(BuilderStatus.ITEM_TEMP_CONN);
                    }
                    else
                    {
                        StringBuilder sb = new StringBuilder();
                        sb.Append("感温电缆连接失败");
                        sb.Append(" GlobalVar.TEMP_CONN_STATE: " + GlobalVar.TEMP_CONN_STATE);
                        sb.Append(" conState: " + conState);
                        //MainLog.Error("感温电缆连接失败", true);
                        MainLog.Error(sb.ToString(), true);

                        //if (GlobalVar.TEMP_CONN_STATE != conState)
                        //{
                        BuilderStatus.SetStop(BuilderStatus.ITEM_TEMP_CONN);
                        //感温电缆连接中断，报警写入数据库报警列表。
                        ConnectionFailureEvent?.Invoke(deviceId);
                        MainLog.Error("感温电缆状态变更！");
                        //}
                        GlobalVar.TEMP_CONN_STATE = conState;
                    }
                }

                //if (GlobalVar.TEMP_CONN_STATE && !firstStart)
                //{
                //    firstStart = true;
                //    Task.Run(()=> ReadTemprature());
                //}

                //await Task.Delay(120000);
                //Thread.Sleep(ConnectInterval);
            }
            catch (Exception ex)
            {
                MainLog.Error(ex);
            }
        }

        /// <summary>
        /// 连接上时，第一次读取调用
        /// 读取成功，直接写入数据库
        /// </summary>
        public async void ReadTemprature()
        {
            MainLog.Debug("启动感温电缆读取线程。");
            //读取数据之后，将数据输出，解析过程在Manager中处理。
            while (true)
            {
                //if (reading)
                //    return;
                //else
                //    reading = true;
                try
                {
                    //List<TempratureModel> dicData = new List<TempratureModel>();
                    for (byte i = startId; i <= endId; i++)
                    {
                        if (GlobalVar.TEMP_CONN_STATE == false)
                        {
                            break;
                        }

                        if (!GlobalVar.tempCache[i].IsEnable)
                        {
                            //StringBuilder sb = new StringBuilder();
                            //sb.Append(" 感温电缆不可用！");
                            //sb.Append(" 电缆编号："+ i);
                            //MainLog.Info(sb.ToString(), true);
                            continue;
                        }
                        //IsEnable == false时, 屏蔽感温电缆。
                        //if (tempCache.TryGetValue(i, out TempratureModel model))
                        //{
                        //    if (!model.IsEnable)
                        //    {
                        //        continue;
                        //    }
                        //}

                        if (ReadTemprature(i, out short[] result))
                        {
                            //解析
                            GlobalVar.connectioinCache = true;
                            GlobalVar.disableCache = false;
                            GlobalVar.tempCache[i].IsValid = true;
                            GlobalVar.tempCache[i].IsEnable = true;
                            GlobalVar.tempCache[i].ContinuousFailCount = 0;
                            //GlobalVar.tempCache[i].Values = result.Select(v => { return Convert.ToDouble(v / 10d); }).ToList();
                            //GlobalVar.tempCache[i].UpdatedTime = DateTime.Now;
                            //数据读出之后，不需要写到缓存中，直接写入数据库就行了。
                            GlobalUtils.UpdateCableData(i, new TempratureModel(i, result) { IsValid = true, IsEnable = true });
                        }
                        else
                        {
                            //成功了，直接写入数据库就行了。
                            //失败了，需要计入次数。
                            //超过3次，则将IsEnable设置为false.
                            //如果已然Disabled之后，就不再检查该部分了。
                            GlobalVar.tempCache[i].ContinuousFailCount++;
                            if (GlobalVar.tempCache[i].ContinuousFailCount == 5)
                            {
                                GlobalVar.tempCache[i].IsValid = false;
                                //GlobalVar.tempCache[i].IsEnable = false;
                                StringBuilder sb = new StringBuilder();
                                sb.Append(" 感温电缆已多次读取数据失败，请检查该感温电缆!");
                                sb.Append(" 感温电缆编号：" + i);
                                MainLog.Error(sb.ToString(), true);

                                //写入报警的事件，需要输出到主程序。
                                CableDisabledEvent?.Invoke(i, false);
                                //record.AddAlarmTo3D(4, "感温电缆" + item.CableId, "温度读取故障。");
                            }
                        }
                        await Task.Delay(ReadInterval);
                    }

                    //int count = tempCache.Where(t => t.Value.Valid).Count();
                    if (!GlobalVar.tempCache.Values.Where(t => t.IsValid).Any())
                    {
                        GlobalVar.TEMP_CONN_STATE = false;
                        MainLog.Error("感温电缆数据读取出现故障。", true);
                        BuilderStatus.SetStop(BuilderStatus.ITEM_TEMP_CONN);
                        Close();
                        await Task.Delay(10000);
                        break;
                    }
                }
                catch (Exception ex)
                {
                    MainLog.Error(ex.ToString(), false);
                }
            }
            MainLog.Error("感温电缆读取线程结束 System.OutOfMemoryException", true);
            GlobalVar.disableCache = true;
        }

        private void Close()
        {
            try
            {
                CloseEvent?.Invoke(deviceId);
                master.ConnectClose();
            }
            catch (Exception ex)
            {
                MainLog.Error(ex);
            }
        }

        public void Dispose()
        {
            try
            {
                master.ConnectClose();
            }
            catch (Exception ex)
            {
                MainLog.Error(ex);
            }
        }

        public bool Connect()
        {
            try
            {
                master = new ModbusTcpNet(ip, 1200);
                master.AddressStartWithZero = false;
                master.ConnectTimeOut = 1000;

                return master.ConnectServer().IsSuccess;
            }
            catch (Exception ex)
            {
                MainLog.Error(ex);
                return false;
            }
        }
    }
}
